package com.xuecheng.manage_cms.service;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.xuecheng.framework.domain.cms.CmsConfig;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsSite;
import com.xuecheng.framework.domain.cms.CmsTemplate;
import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.domain.cms.response.CmsCode;
import com.xuecheng.framework.domain.cms.response.CmsPageResult;
import com.xuecheng.framework.domain.course.CourseBase;
import com.xuecheng.framework.domain.course.response.CmsPostPageResult;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;
import com.xuecheng.framework.model.response.ResponseResult;
import com.xuecheng.manage_cms.config.RabbitmqConfig;
import com.xuecheng.manage_cms.dao.CmsConfigRepository;
import com.xuecheng.manage_cms.dao.CmsPageRepository;
import com.xuecheng.manage_cms.dao.CmsSiteRepository;
import com.xuecheng.manage_cms.dao.CmsTemplateRepository;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Service
public class PageService {

    @Autowired
    CmsPageRepository cmsPageRepository;
    @Autowired
    CmsConfigRepository cmsConfigRepository;
    @Autowired
    CmsTemplateRepository cmsTemplateRepository;
    @Autowired
    CmsSiteRepository cmsSiteRepository;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    GridFsTemplate gridFsTemplate;
    @Autowired
    GridFSBucket gridFSBucket;
    @Autowired
    RabbitTemplate rabbitTemplate;

    /**
     * 页面列表分页查询
     * @param page 当前页码 从1开始计数
     * @param size 页面显示个数
     * @param queryPageRequest 查询条件
     * @return 页面列表
     */
    public QueryResponseResult<CourseBase> findList(int page, int size, QueryPageRequest queryPageRequest){
        if(page<=0){
            page=1;
        }
        page=page-1;
        if(size<=0){
            size=10;
        }
        //定义条件匹配器ExampleMatcher.GenericPropertyMatchers.contains()模糊查询字段定义
        ExampleMatcher matcher=ExampleMatcher.matching()
                .withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains())
                .withMatcher("pageName", ExampleMatcher.GenericPropertyMatchers.contains());
        CmsPage cmsPage=new CmsPage();
        if (StringUtils.isNotEmpty(queryPageRequest.getSiteId())){
            cmsPage.setSiteId(queryPageRequest.getSiteId());
        }
        if(StringUtils.isNotEmpty(queryPageRequest.getPageId())){
            cmsPage.setPageId(queryPageRequest.getPageId());
        }
        if(StringUtils.isNotEmpty(queryPageRequest.getPageAliase())){
            cmsPage.setPageAliase(queryPageRequest.getPageAliase());
        }
        if(StringUtils.isNotEmpty(queryPageRequest.getPageType())){
            cmsPage.setPageType(queryPageRequest.getPageType());
        }
        Example<CmsPage> example=Example.of(cmsPage,matcher);
        Pageable pageable= PageRequest.of(page, size);
        Page<CmsPage> cmsPages=cmsPageRepository.findAll(example,pageable);
        QueryResult queryResult=new QueryResult();
        queryResult.setList(cmsPages.getContent()); //数据列表
        queryResult.setTotal(cmsPages.getTotalPages()); //分页数
        QueryResponseResult<CourseBase> queryResponseResult=new QueryResponseResult<CourseBase>(CommonCode.SUCCESS,queryResult);
        return queryResponseResult;
    }

    /**
     *添加页面
     * @param cmsPage
     * @return
     */
    public CmsPageResult addCmsPage(CmsPage cmsPage){

        //检查是否存在
        if(cmsPage==null){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        if(cmsPageRepository.findCmsPageByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(),
               cmsPage.getSiteId(),cmsPage.getPageWebPath())!=null){
            ExceptionCast.cast(CmsCode.CMS_ADDPAGE_EXISTSNAME);
        }
           cmsPage.setSiteId(cmsPage.getSiteId());
            cmsPageRepository.save(cmsPage);
            //添加成功
            return new CmsPageResult(CommonCode.SUCCESS,cmsPage);
    }

    //根据id查询页面
    public CmsPage findById(String id) {
        Optional<CmsPage> cmsPage=cmsPageRepository.findById(id);
        if(cmsPage.isPresent()){
            return cmsPage.get();
        }
        return null;
    }

    /**
     * 修改页面信息
     * @param id
     * @param cmsPage
     * @return
     */
    public CmsPageResult edit(String id, CmsPage cmsPage) {
        if(findById(id)==null){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
             CmsPage one=findById(id);
            one.setPageName(cmsPage.getPageName());
            one.setPageAliase(cmsPage.getPageAliase());
            one.setTemplateId(cmsPage.getTemplateId());
            one.setSiteId(cmsPage.getSiteId());
            one.setPageWebPath(cmsPage.getPageWebPath());
            one.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
            one.setDataUrl(cmsPage.getDataUrl());
            CmsPage save=cmsPageRepository.save(one);
          return new CmsPageResult(CommonCode.SUCCESS,save);
    }

    public ResponseResult deleteById(String id) {
        CmsPage one=findById(id);
        if(one==null){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
            cmsPageRepository.deleteById(id);
            return new ResponseResult(CommonCode.SUCCESS);
    }

    /**
     * 通过id获取cmsConfig
     * @param id
     * @return
     */
    public CmsConfig getCmsConfigById(String id){
       Optional<CmsConfig> optional= cmsConfigRepository.findById(id);
       if(optional.isPresent()){
           CmsConfig config=optional.get();
           return config;
       }
       return null;
    }

    //页面静态化
   public String getPageHtml(String pageId){
      Map model=getModelByPageId(pageId);
      if(model==null){
          ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
      }
      String templateContent=this.getTemplateByPageId(pageId);
      if(StringUtils.isEmpty(templateContent)){
          ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
      }
      //都不为空执行页面静态化方法
       String html = generateHtml(templateContent, model);
      if(StringUtils.isEmpty(html)){
          //生产的静态页面为空
          ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
      }
        return html;
   }

   //页面静态化执行方法
    public String generateHtml(String templateContent, Map model) {
        //生产配置类
        Configuration configuration=new Configuration(Configuration.getVersion());
        //模板加载器
        StringTemplateLoader templateLoader=new StringTemplateLoader();
        templateLoader.putTemplate("template",templateContent);
        //配置模板加载器
        configuration.setTemplateLoader(templateLoader);
        //获取模板
       try {
           Template template=configuration.getTemplate("template");
           String html= FreeMarkerTemplateUtils.processTemplateIntoString(template,model);
           return html;
       }catch (Exception e){
           e.printStackTrace();
       }
        return null;
    }


    public String getTemplateByPageId(String pageId){
        CmsPage cmsPage=this.findById(pageId);
        if(cmsPage==null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXITS);
        }
        String templateId=cmsPage.getTemplateId();
        if(StringUtils.isEmpty(templateId)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        Optional<CmsTemplate> optional= cmsTemplateRepository.findById(templateId);
        if(optional.isPresent()){
            CmsTemplate template=optional.get();
            //取出模板文件内容
            String  filedId=template.getTemplateFileId();
            GridFSFile gridFsFile=gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(filedId)));
            //打开下载流对象
            GridFSDownloadStream gridFSDownloadStream=gridFSBucket.openDownloadStream(gridFsFile.getObjectId());
            //创建GridFsResource
            GridFsResource gridFsResource=new GridFsResource(gridFsFile,gridFSDownloadStream);
       try {
                String content= IOUtils.toString(gridFsResource.getInputStream(),"UTF-8");
                return content;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
   }

    //获取页面模型数据
    public Map getModelByPageId(String pageId){
        CmsPage cmsPage=this.findById(pageId);
        if(cmsPage==null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXITS);
        }
        //获取dataURL 进行判断
        String  dataUrl=cmsPage.getDataUrl();
        if(StringUtils.isEmpty(dataUrl)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        ResponseEntity<Map> responseEntity= restTemplate.getForEntity(dataUrl,Map.class);
        Map body=responseEntity.getBody();
        return body;
    }


    //页面发布方法
    public ResponseResult postPage(String pageId){
        //页面静态化
        String pageHtml=this.getPageHtml(pageId);
        if(StringUtils.isEmpty(pageHtml)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        //保存静态化文件
        CmsPage cmsPage=this.saveHtml(pageId,pageHtml);
        //发布消息
        sendPostPage(pageId);
        return new ResponseResult(CommonCode.SUCCESS);
    }


    //向mq发送消息
    private void sendPostPage(String pageId){
        CmsPage cmsPage = this.findById(pageId);
        if(cmsPage == null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXITS);
        }

        Map<String,String> map=new HashMap();
        map.put("pageId",pageId);
        //消息内容
        String msg= JSON.toJSONString(map);
        //获取站点ID作为routingKey
        String siteId=cmsPage.getSiteId();
        //发送队列消息 参数1,交换机 2.routingKey 3.消息内容
        rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_CMS_POSTPAGE,siteId,msg);
    }

    //保存静态页面内容到gridFS
    private CmsPage saveHtml(String pageId,String content){
        //查询页面内容
        CmsPage cmsPage=this.findById(pageId);
        if(cmsPage==null){
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
       // 保存之前，先查看是否有文件，有则删除
//        if(StringUtils.isNotEmpty(cmsPage.getHtmlFileId())){
//            gridFsTemplate.delete(Query.query(Criteria.where("_id").is(cmsPage.getPageHtml())));
//        }
        //保存文件到gridFS

        ObjectId objectId=null;
        try {
        InputStream  inputStream = IOUtils.toInputStream(content,"utf-8");
        objectId=gridFsTemplate.store(inputStream,cmsPage.getPageName());
        } catch (IOException e) {
            e.printStackTrace();
        }

        //将文件id保存到cmspage中
        cmsPage.setHtmlFileId(objectId.toString());
        cmsPageRepository.save(cmsPage);
        return cmsPage;
    }

    //添加页面，如果已存在则更新页面
    public CmsPageResult save(CmsPage cmsPage) {
        //校验页面是否存在，根据页面名称、站点Id、页面webpath查询
        CmsPage cmsPage1 =
                cmsPageRepository.findCmsPageByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(),
                        cmsPage.getSiteId(), cmsPage.getPageWebPath());
        if(cmsPage1 !=null){
        //更新
            return this.edit(cmsPage1.getPageId(),cmsPage);
        }else{
        //添加
            return this.addCmsPage(cmsPage);
        }
    }
    //一键发布
    public CmsPostPageResult postPageQuick(CmsPage cmsPage) {
       CmsPageResult save= this.save(cmsPage);
       if(!save.isSuccess()){
          return new CmsPostPageResult(CommonCode.FAIL,null);
       }
       CmsPage cmsPage1=save.getCmsPage();
       String pageId=cmsPage1.getPageId();
       ResponseResult responseResult=  this.postPage(pageId);
       if(!responseResult.isSuccess()){
           return new CmsPostPageResult(CommonCode.FAIL,null);
       }
        String siteId=cmsPage1.getSiteId();
       CmsSite cmsSite=findCmsSiteById(siteId);
        //得到页面的url
        //页面url=站点域名+站点webpath+页面webpath+页面名称
        //站点id
        //站点域名
        String siteDomain = cmsSite.getSiteDomain();
        //站点web路径
        String siteWebPath = cmsSite.getSiteWebPath();
        //页面web路径
        String pageWebPath = cmsPage1.getPageWebPath();
        //页面名称
        String pageName = cmsPage1.getPageName();
        //页面的web访问地址
        String pageUrl = siteDomain+siteWebPath+pageWebPath+pageName;
        return new CmsPostPageResult(CommonCode.SUCCESS,pageUrl);
    }

    //根据id查询站点信息
    public CmsSite findCmsSiteById(String siteId){
        Optional<CmsSite> optional = cmsSiteRepository.findById(siteId);
        if(optional.isPresent()){
            return optional.get();
        }
        return null;
    }

}
